
#include <iostream>
#include <stdlib.h>

#include <GL/glut.h>


#include "imageloader.h"//the loader of bmp images, found on internet

using namespace std;


//Ids of textures
GLuint _texture1Id, _texture2Id, _metalTextureId, _currentTextureId; 

void handleKeypress(unsigned char key, int x, int y) {
	switch (key) {
		case 27: //Escape key
			exit(0);
		case 'a':
			//change for texture 1
                   	_currentTextureId = _texture1Id;
			glutPostRedisplay();
			break;
 		case 'b':
			//change for texture 2
			_currentTextureId = _texture2Id;
			glutPostRedisplay();
			break;
			
              
	}
}

//Makes the image into a texture, and returns the id of the texture
GLuint loadTexture(Image* image) {
	GLuint textureId;
	glGenTextures(1, &textureId); //Make room for our texture
	glBindTexture(GL_TEXTURE_2D, textureId); //Tell OpenGL which texture to edit
	//Map the image to the texture
	glTexImage2D(GL_TEXTURE_2D,                //Always GL_TEXTURE_2D
				 0,                            //0 for now
				 GL_RGB,                       //Format OpenGL uses for image
				 image->width, image->height,  //Width and height
				 0,                            //The border of the image
				 GL_RGB, //GL_RGB, because pixels are stored in RGB format
				 GL_UNSIGNED_BYTE, //GL_UNSIGNED_BYTE, because pixels are stored
				                   //as unsigned numbers
				 image->pixels);               //The actual pixel data
	return textureId; //Returns the id of the texture
}


void handleResize(int w, int h) {
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0, (float)w / (float)h, 1.0, 200.0);
}

void DrawCylinder()
{
	glPushMatrix(); 
	
	GLUquadric* params = gluNewQuadric(); 
	gluQuadricTexture(params,GL_TRUE); 
	
	//rotate to place the cone correctly and hide the limit of the texturing
	glRotated(-110, 0, 1, 0);
	glRotated(-90, 1, 0, 0);
	
	//gluCylinder(GLUquadric* params,base,top,height,slices,stacks);
	gluCylinder(params,0.5,0,1.6,20,1); 
		
	gluDeleteQuadric(params); 
	
	glPopMatrix(); 
}

void DrawCube()
{
	glPushMatrix(); 

	glRotated(110, 0, 1, 0);
   	//Draw cube
	glBegin(GL_QUADS);
		//front face
		glTexCoord2d(0,1);  glVertex3d(0,0,0);
		glTexCoord2d(0,0);  glVertex3d(1,0,0);
		glTexCoord2d(1,0);  glVertex3d(1,-1,0);
		glTexCoord2d(1,1);  glVertex3d(0,-1,0);
		
		//right face
		glTexCoord2d(0,1);  glVertex3d(1,0,0);
		glTexCoord2d(0,0);  glVertex3d(1,0,-1);
		glTexCoord2d(1,0);  glVertex3d(1,-1,-1);
		glTexCoord2d(1,1);  glVertex3d(1,-1,0);
		
		//up face
		glTexCoord2d(0,1);  glVertex3d(0,0,0);
		glTexCoord2d(0,0);  glVertex3d(1,0,0);
		glTexCoord2d(1,0);  glVertex3d(1,0,-1);
		glTexCoord2d(1,1);  glVertex3d(0,0,-1);
	glEnd();

	glPopMatrix();
}

void DrawSphere()
{
	glPushMatrix(); 
	
	//load parameters
	GLUquadric* params = gluNewQuadric(); 
	//Activate texturing
	gluQuadricTexture(params,GL_TRUE); 
	
	//Hide limit of texturing
	glRotated(180, 0, 1, 0);
	glRotated(-110, 1, 0, 0);
	//gluSphere(GLUquadric* params,radius,slices,stacks);;
	gluSphere(params,1,20,20); 
	
	//delete quadric
	gluDeleteQuadric(params); 
	
	//set at it was previously
	glPopMatrix(); 
}

void DrawPlane()
{
	glPushMatrix(); 

	glBegin(GL_QUADS);
		//texture will be tiled
		glTexCoord2d(0,10);  glVertex3d(-5,-1,-5);
		glTexCoord2d(0,0);  glVertex3d(5,-1,-5);
		glTexCoord2d(10,0);  glVertex3d(5,-1,5);
		glTexCoord2d(10,10);  glVertex3d(-5,-1,5);
	glEnd();

	glPopMatrix(); 
}

void drawScene() 
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
	//Set camera position
	gluLookAt(0,3,-8,0,0,0,0,1,0);

	//Texture settings
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	//Select the texture for objects
	glBindTexture(GL_TEXTURE_2D, _currentTextureId);

	//Cube in the middle
	glPushMatrix();
		DrawCube();
	glPopMatrix();
	
	//Cylinder on the right
	glPushMatrix();
		glTranslated(-2,0,-2);
		DrawCylinder();
	glPopMatrix();

        //Sphere on the left
	glPushMatrix();
		glTranslated(2,0,-2);
		DrawSphere();
	glPopMatrix();

	//Select the texture for the ground
	glBindTexture(GL_TEXTURE_2D, _metalTextureId);

	//Plane on the origin
        DrawPlane();
	
	glutSwapBuffers();
}

void initRendering() {

 	glMatrixMode( GL_PROJECTION );
    	glLoadIdentity();
    	gluPerspective(70,(double)800/600,1,1000);

    	glEnable(GL_DEPTH_TEST);
	//allow texturing
	glEnable(GL_TEXTURE_2D);

	//set light settings
	GLfloat ambientLight[] = {0.2f, 0.2f, 0.2f, 1.0f};
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
	GLfloat directedLight[] = {0.7f, 0.7f, 0.7f, 1.0f};
	GLfloat directedLightPos[] = {-10.0f, 15.0f, 20.0f, 0.0f};
	glLightfv(GL_LIGHT0, GL_DIFFUSE, directedLight);
	glLightfv(GL_LIGHT0, GL_POSITION, directedLightPos);

	/*load textures in memory
          use a loadBMP function found on the internet
	*/
	Image* image = loadBMP("metal.bmp");
	_metalTextureId = loadTexture(image);
	delete image;

	Image* image2 = loadBMP("texture2.bmp");
	_texture1Id = loadTexture(image2);
	delete image2;

	Image* image3 = loadBMP("texture1.bmp");
	_texture2Id = loadTexture(image3);
	delete image3;

	_currentTextureId = _texture2Id;
}

int main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(800, 600);
	
	glutCreateWindow("Textures - videotutorialsrock.com");
	initRendering();
	
	glutDisplayFunc(drawScene);
	glutKeyboardFunc(handleKeypress);
	glutReshapeFunc(handleResize);

	glutMainLoop();
	return 0;
}









